﻿using System;
using System.IO;
using Ant.Interface.GlobalInfo;
using Ant.Interface.Log;
using NLog;
using NLog.Config;

namespace Ant.BasicPlugIn.Log
{
    public class LogController : ILogController
    {
        private readonly LogEventInfo _logEventInfo = new LogEventInfo();
        private Logger _logger;

        public LogController()
        {
            var configPath = Path.Combine(EnvironmentInfo.ConfigPhysicalPath, @"Log\NLog.xml");
            if (!File.Exists(configPath))
            {
                SimpleLog.Info(string.Format("找不到日志配置文件，路径：{0}。", configPath));
                return;
            }
            var config = new XmlLoggingConfiguration(configPath);
            LogManager.Configuration = config;

            //设置记录器。
            SetLogger("Default");
        }

        #region "ILogController Member"

        public void SetLogger(Type loggerType)
        {
            _logger = LogManager.GetCurrentClassLogger(loggerType);
        }

        public void SetLogger(string loggerName, Type loggerType = null)
        {
            _logger = loggerType == null ? LogManager.GetLogger(loggerName) : LogManager.GetLogger(loggerName, loggerType);
        }

        public void Debug(string categoryName, string message, Exception exception = null)
        {
            Log(LogLevel.Debug, categoryName, message, exception);
        }

        public void Error(string categoryName, string message, Exception exception = null)
        {
            Log(LogLevel.Error, categoryName, message, exception);
        }

        public void Fatal(string categoryName, string message, Exception exception = null)
        {
            Log(LogLevel.Fatal, categoryName, message, exception);
        }

        public void Info(string categoryName, string message, Exception exception = null)
        {
            Log(LogLevel.Info, categoryName, message, exception);
        }

        public void Trace(string categoryName, string message, Exception exception = null)
        {
            Log(LogLevel.Trace, categoryName, message, exception);
        }

        public void Warn(string categoryName, string message, Exception exception = null)
        {
            Log(LogLevel.Warn, categoryName, message, exception);
        }

        public void Monitor(Action action, string categoryName, string actionDescription, Action<Exception> errorAction = null, Action finallyAction = null, string startInfo = "开始{0}。", string endInfo = "{0}成功。", string errorInfo = "{0}失败。", string finallyInfo = null, bool isFatal = false, bool isMonitorLog = true, bool isThrowError = true)
        {
            if (action == null)
                throw new ArgumentNullException("action", "需要执行的方法不能为空。");
            if (string.IsNullOrWhiteSpace(categoryName))
                throw new ArgumentNullException("categoryName", "记录的分类不能为空。");
            if (string.IsNullOrWhiteSpace(actionDescription))
                throw new ArgumentNullException("actionDescription", "动作描述不能为空。");

            if (startInfo != null)
                startInfo = string.Format(startInfo, actionDescription);
            if (errorInfo != null)
                endInfo = string.Format(endInfo, actionDescription);
            if (errorInfo != null)
                errorInfo = string.Format(errorInfo, actionDescription);
            if (finallyInfo != null)
                finallyInfo = string.Format(finallyInfo, actionDescription);

            if (isMonitorLog)
                Info("System_Monitor", string.Format("监控开始，动作说明：{0}。", actionDescription));
            try
            {
                if (!string.IsNullOrWhiteSpace(startInfo))
                {
                    Info(categoryName, startInfo);
                }
                action();
                if (!string.IsNullOrWhiteSpace(endInfo))
                {
                    Info(categoryName, endInfo);
                }
            }
            catch (Exception exception)
            {
                if (!string.IsNullOrWhiteSpace(errorInfo))
                {
                    if (isFatal)
                    {
                        Fatal(categoryName, endInfo, exception);
                    }
                    else
                    {
                        Error(categoryName, errorInfo, exception);
                    }
                }

                if (errorAction != null)
                    errorAction(exception);

                if (isThrowError)
                    throw;
            }
            finally
            {
                if (!string.IsNullOrWhiteSpace(finallyInfo))
                    Info(categoryName, finallyInfo);
                if (finallyAction != null)
                    finallyAction();
                if (isMonitorLog)
                    Info(categoryName, string.Format("监控结束，动作说明：{0}。", actionDescription));
            }
        }

        #endregion "ILogController Member"

        #region "Private Method"

        private void Log(LogLevel level, string categoryName, string message, Exception exception = null)
        {
            //_logEventInfo.Properties.Clear();
            _logEventInfo.Level = level;
            _logEventInfo.Message = message;
            _logEventInfo.Exception = exception;
            _logEventInfo.LoggerName = _logger.Name;
            _logEventInfo.Properties["categoryName"] = categoryName;
            _logEventInfo.TimeStamp = DateTime.Now;
            _logger.Log(_logEventInfo);
        }

        #endregion "Private Method"
    }
}